#ifndef _RDB_DRIVER_EXCEPTIONS_H_
#define _RDB_DRIVER_EXCEPTIONS_H_

#include <buildspec.h>
#include <GSTenums.h>
#include <Client/ClientUtils/Network/NetworkInterface.h>
#include <exceptions/GSTRuntimeException.h>

#include <string>

namespace GST {

	//exceptions:
namespace exceptions
{

	void parseException(const std::string& db_errormessage, const std::string& query);

	/**
	 * Throw if try to use connection but not possible (e.g. wrong password)
	 */
	class ConnectionError
		: public NoConnection
	{
	public:
		GST::ClientUtils::Host host;
		std::string dbname;

		ConnectionError(const std::string & throwLocation, const std::string& msg, const GST::ClientUtils::Host& h, const std::string& dbname)
			: NoConnection(throwLocation,msg)
			, host(h)
			, dbname(dbname)
		{
			this->_msg += " (refers connection to: "+h.user+"@"+h.ip+" to database "+dbname+". )";
		}
		virtual ~ConnectionError() throw()
		{}
	};

	/**
	 * Throw if try to use connection but not possible (e.g. to many connections)
	 */
	class ToManyConnections
		: public ServerCrowded
	{
	public:
		GST::ClientUtils::Host host;
		std::string dbname;

		ToManyConnections(const std::string & throwLocation, const std::string& msg, const GST::ClientUtils::Host& h, const std::string& dbname)
			: ServerCrowded(throwLocation,msg)
			, host(h)
			, dbname(dbname)
		{
			this->_msg += " (refers connection to: "+h.user+"@"+h.ip+" to database "+dbname+". )";
		}
		virtual ~ToManyConnections() throw()
		{}
	};

	/**
	 * Thrown if connection terminated abnormal (e.g. db crash)
	 */
	class ConnectionTerminated
		: public ConnectionError
	{
	public:
		std::string query;
		
		ConnectionTerminated(const std::string & throwLocation, const std::string& msg, const GST::ClientUtils::Host& h, const std::string & dbname, const std::string & query)
			: ConnectionError(throwLocation,msg,h,dbname)
			, query(query)
		{}
		virtual ~ConnectionTerminated() throw()
		{}
		
	};

	class SQLError
		: public GSTRuntimeException 
	{
	public:
		std::string query;
		std::string db_errormessage;

		SQLError(const std::string & throwLocation, const std::string & db_errormessage, const std::string & query)
			: GSTRuntimeException(throwLocation,"Query error. "+db_errormessage)
			, query(query)
			, db_errormessage(db_errormessage)
		{}

		std::string getQuery() const
		{
			return this->query;
		}
		std::string getDBMessage() const
		{
			return this->db_errormessage;
		}

		virtual ~SQLError() throw() 
		{}
	};

	class SQLSyntaxError
		: public SQLError
	{
	public:
		SQLSyntaxError(const std::string & throwLocation, const std::string & db_errormessage, const std::string & query)
			: SQLError(throwLocation,db_errormessage,query)
		{}
		
		virtual ~SQLSyntaxError() throw()
		{}
	};

	class ConstraintViolation
		: public SQLError
	{  
	public:
		ConstraintViolation(const std::string & throwLocation, const std::string & db_errormessage, const std::string & query)
			: SQLError(throwLocation,db_errormessage,query)
		{}

		virtual ~ConstraintViolation() throw()
		{}
	};

	class DataTypeUnkown
		: public GSTRuntimeException
	{
	public:
		DataTypeUnkown(const std::string & throwLocation, const std::string& dataTypeString)
			: GSTRuntimeException(throwLocation,"")
		{ 
			this->_msg = "Data type string \""+dataTypeString+"\" not registered."; 
		}
	};

	class TableNotFound
		: public SQLSyntaxError
	{
	public:
		TableNotFound(const std::string & throwLocation, const SQLSyntaxError& e, const std::string& table)
			: SQLSyntaxError(throwLocation,e.db_errormessage, e.query)
		{ 
			this->_msg = "Table \""+table+"\" not found. Query error message: "+e.getMessage();
		}
	};

	class InsufficientAccess
		: public GSTRuntimeException
	{
	public:
		InsufficientAccess(const std::string & throwLocation, const std::string & operation)
			: GSTRuntimeException(throwLocation)
		{ 
			this->_msg = "Insufficient right to perform operation "+operation;
		}
	};
}//of ns exceptions
}//of ns GST
#endif //_RDB_DRIVER_EXCEPTIONS_H_